namespace Spring.Expressions.Parser.antlr.debug
{

	/* ANTLR Translator Generator
	 * Project led by Terence Parr at http://www.jGuru.com
	 * Software rights: http://www.antlr.org/license.html
	 */

	//
	// ANTLR C# Code Generator by Micheal Jordan
	//                            Kunle Odutola       : kunle UNDERSCORE odutola AT hotmail DOT com
	//                            Anthony Oguntimehin
	//

    using Stack = System.Collections.Stack;
	using antlr;
	using BitSet = antlr.collections.impl.BitSet;

	/// <summary>
	/// Specifies the behaviour required (i.e. parser modifications) 
	/// specifically to support parse tree debugging and derivation.
	/// </summary>
	/// <remarks>
	/// <para>
	/// Override the standard matching and rule entry/exit routines
	/// to build parse trees.  This class is useful for 2.7.3 where
	/// you can specify a superclass like
	/// </para>
	/// <para>
	/// class TinyCParser extends Parser(ParseTreeDebugParser);
	/// </para>
	/// </remarks>
	public class ParseTreeDebugParser : LLkParser 
	{
		/// <summary>
		/// Each new rule invocation must have it's own subtree. Tokens are
		/// added to the current root so we must have a stack of subtree roots.
		/// </summary>
		protected Stack currentParseTreeRoot = new Stack();

		/// <summary>
		/// Track most recently created parse subtree so that when parsing
		/// is finished, we can get to the root.
		/// </summary>
		protected ParseTreeRule mostRecentParseTreeRoot = null;

		/// <summary>
		/// For every rule replacement with a production, we bump up count.
		/// </summary>
		protected int numberOfDerivationSteps = 1; // n replacements plus step 0

		public ParseTreeDebugParser(int k_) : base(k_)
		{
		}

		public ParseTreeDebugParser(ParserSharedInputState state, int k_) : base(state, k_)
		{
		}

		public ParseTreeDebugParser(TokenBuffer tokenBuf, int k_) : base(tokenBuf, k_)
		{
		}

		public ParseTreeDebugParser(TokenStream lexer, int k_) : base(lexer,k_)
		{
		}

		public ParseTree getParseTree() 
		{
			return mostRecentParseTreeRoot;
		}

		public int getNumberOfDerivationSteps() 
		{
			return numberOfDerivationSteps;
		}

		public override void match(int i) 			// throws MismatchedTokenException, TokenStreamException 
		{
			addCurrentTokenToParseTree();
			base.match(i);
		}

		public override void match(BitSet bitSet) 	// throws MismatchedTokenException, TokenStreamException 
		{
			addCurrentTokenToParseTree();
			base.match(bitSet);
		}

		public override void matchNot(int i) 		// throws MismatchedTokenException, TokenStreamException
		{
			addCurrentTokenToParseTree();
			base.matchNot(i);
		}

		/// <summary>
		/// Adds LT(1) to the current parse subtree.
		/// </summary>
		/// <remarks>
		/// <para>
		/// Note that the match() routines add the node before checking for 
		/// correct match.  This means that, upon mismatched token, there 
		/// will a token node in the tree corresponding to where that token 
		/// was expected.  For no viable alternative errors, no node will 
		/// be in the tree as nothing was matched() (the lookahead failed 
		/// to predict an alternative).
		/// </para>
		/// </remarks>
		protected void addCurrentTokenToParseTree() 		// throws TokenStreamException 
		{
			if (inputState.guessing > 0) 
			{
				return;
			}
			ParseTreeRule root = (ParseTreeRule) currentParseTreeRoot.Peek();
			ParseTreeToken tokenNode = null;
			if ( LA(1) == Token.EOF_TYPE ) 
			{
				tokenNode = new ParseTreeToken(new antlr.CommonToken("EOF"));
			}
			else 
			{
				tokenNode = new ParseTreeToken(LT(1));
			}
			root.addChild(tokenNode);
		}

		/// <summary>
		/// Create a rule node, add to current tree, and make it current root
		/// </summary>
		/// <param name="s"></param>
		public override void traceIn(string s) 				// throws TokenStreamException 
		{
			if (inputState.guessing > 0) 
			{
				return;
			}
			ParseTreeRule subRoot = new ParseTreeRule(s);
			if ( currentParseTreeRoot.Count > 0 ) 
			{
				ParseTreeRule oldRoot = (ParseTreeRule) currentParseTreeRoot.Peek();
				oldRoot.addChild(subRoot);
			}
			currentParseTreeRoot.Push(subRoot);
			numberOfDerivationSteps++;
		}

		/// <summary>
		/// Pop current root; back to adding to old root
		/// </summary>
		/// <param name="s"></param>
		public override void traceOut(string s) 				// throws TokenStreamException
		{
			if (inputState.guessing > 0) 
			{
				return;
			}
			mostRecentParseTreeRoot = (ParseTreeRule) currentParseTreeRoot.Pop();
		}
	}
}
